package cn.regexp.job.service.jobhandler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.regexp.common.core.domain.SeckillProductVo;
import cn.regexp.common.core.web.Result;
import cn.regexp.job.enums.JobRedisKeyEnum;
import cn.regexp.job.feign.SeckillProductFeignApi;
import com.alibaba.fastjson.JSON;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author Regexpei
 * @date 2024/7/5 23:09
 * @description 秒杀商品缓存任务
 */
@Component
public class SeckillProductCacheJob {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SeckillProductFeignApi seckillProductFeignApi;
    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @XxlJob("RefreshSeckillProductCache")
    public ReturnT<String> refreshSeckillProductCache() {
        String param = XxlJobContext.getXxlJobContext().getJobParam();
        XxlJobHelper.log("RefreshSeckillProductCache: refresh seckill product cache, start. " + "Param: {}", param);

        // noinspection rawtypes
        CompletableFuture[] refreshTasks = StrUtil.split(param, ",").stream()
                .map(time -> CompletableFuture.runAsync(() -> doWork(time), taskExecutor))
                .toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(refreshTasks);

        XxlJobHelper.log("RefreshSeckillProductCache: refresh seckill product cache, finish.");
        return ReturnT.SUCCESS;
    }

    private void doWork(String time) {
        // 远程调用，查询秒杀商品数据
        Result<List<SeckillProductVo>> result = seckillProductFeignApi.selectByType(Integer.parseInt(time));

        // 判断远程调用返回结果是否为 null && 返回状态码是否等于 200
        if (result == null || result.hasError()) {
            XxlJobHelper.log("Time: {}, refresh seckill product cache, fail. " + "Result is null or hasError!", time);
            return;
        }

        // 获取返回的秒杀列表数据
        List<SeckillProductVo> vos = result.getData();
        if (CollectionUtil.isEmpty(vos)) {
            XxlJobHelper.log("Time: {}, refresh seckill product cache, finish. " + "SeckillProductVo is empty!", time);
        }

        // 秒杀商品列表 key
        String listRealKey = JobRedisKeyEnum.SECKILL_PRODUCT_LIST.getRealKey(time);
        // 秒杀商品库存 key
        String countRealKey = JobRedisKeyEnum.SECKILL_STOCK_COUNT_HASH.getRealKey(time);

        // 如果 redis 中存在 listRealKey 说明执行过任务
        if (Boolean.TRUE.equals(redisTemplate.hasKey(listRealKey))) {
            redisTemplate.delete(listRealKey);
        }

        // 如果 redis 中存在 countRealKey 说明执行过任务
        if (Boolean.TRUE.equals(redisTemplate.hasKey(countRealKey))) {
            redisTemplate.delete(countRealKey);
        }

        for (SeckillProductVo vo : vos) {
            // 将秒杀商品存到 redis 中
            redisTemplate.opsForHash().put(listRealKey, vo.getId() + "", JSON.toJSONString(vo));
            // 将秒杀商品库存数存到 redis 中
            redisTemplate.opsForHash().put(countRealKey, vo.getId() + "", vo.getCurrentCount() + "");
        }

        XxlJobHelper.log("Time: {}, refresh seckill product cache, success. ", time);

    }
}
